import { Entity } from "../../../../../Core/Module/Entity/Entity";
import { EventSystem } from "../../../../../Core/Module/EventSystem/EventSystem";
import { AwakeSystem, IAwake } from "../../../../../Core/Module/EventSystem/IAwakeSystem";
import { DestroySystem, IDestroy } from "../../../../../Core/Module/EventSystem/IDestroySystem";
import { HashSet } from "../../../../../Support/Share/Lib/Collections/HashSet";
import { Dictionary } from "../../../../../Support/Share/Lib/Dictionary";
import { GetTypeOf, MessageAttribute, GetCustomAttributes, MessageAttrData, FriendOf, ImplementsInterface, ObjectSystemAttribute, ExpandOf, IsAssignableFrom, ResponseTypeAttribute, ResponseTypeAttrData } from "../../../../../Decorator/Decorator";
import { OpcodeHelper } from "./OpcodeHelper";
import { IRequest } from "./IMessage";
import { IActorLocationMessage } from "../ActorLocation/IActorLocationMessage";
import { ActorResponse } from "../ActorLocation/ActorResponse";
import { Log } from "../../../../../Core/Module/Log/Log";
import { IActorMessage } from "../Actor/IActorMessage";

@ImplementsInterface(IAwake)
@ImplementsInterface(IDestroy)
export class OpcodeTypeComponent extends Entity implements IAwake, IDestroy {

    public static Instance: OpcodeTypeComponent;

    public outrActorMessage = new HashSet<number>();

    public readonly requestResponse = new Dictionary<string, string>();

}

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "./OpcodeTypeComponent" {

    interface OpcodeTypeComponent {

        IsOutrActorMessage(opcode: number): boolean;
        GetResponseType(request: string): string;
    }

}

@ExpandOf(OpcodeTypeComponent)
export class OpcodeTypeComponentSystem {

    private static IsOutrActorMessage(self: OpcodeTypeComponent, opcode: number): boolean {
        return self.outrActorMessage.Contains(opcode);
    }

    private static GetResponseType(self: OpcodeTypeComponent, request: string): string {
        let response = self.requestResponse.TryGetValue(request);
        if (!response) {
            throw new Error(`not found response type, request type: ${request}`);
        }
        return response;
    }

}

@FriendOf(OpcodeTypeComponent)
@ObjectSystemAttribute()
export class OpcodeTypeComponentAwakeSystem extends AwakeSystem<OpcodeTypeComponent> {

    Awake(self: OpcodeTypeComponent): void {
        OpcodeTypeComponent.Instance = self;

        self.requestResponse.Clear();

        let types = EventSystem.Instance.GetTypes(GetTypeOf(MessageAttribute));
        for (let type in types) {
            let clazz = types[type];
            let attrs = GetCustomAttributes(clazz);
            if (attrs.length == 0) {
                continue;
            }
            let messageAttribute = attrs[0] as MessageAttrData;
            if (messageAttribute == null) {
                continue;
            }
            let opcode = messageAttribute.Opcode;
            if (OpcodeHelper.IsOuterMessage(opcode) && IsAssignableFrom(clazz, IActorMessage)) {
                self.outrActorMessage.Add(opcode);
            }
            // 检查request response
            if (IsAssignableFrom(clazz, IRequest)) {
                if (IsAssignableFrom(clazz, IActorLocationMessage)) {
                    self.requestResponse.Add(GetTypeOf(clazz), GetTypeOf(ActorResponse));
                    continue;
                }
                let attrs = GetCustomAttributes(clazz);
                if (attrs.length == 0) {
                    Log.Error(`not found responseType: ${GetTypeOf(clazz)}`);
                    continue;
                }
                let responseTypeAttribute = attrs[1] as ResponseTypeAttrData;
                self.requestResponse.Add(GetTypeOf(clazz), responseTypeAttribute.Type);
            }
        }
    }

}

@FriendOf(OpcodeTypeComponent)
@ObjectSystemAttribute()
export class OpcodeTypeComponentDestroySystem extends DestroySystem<OpcodeTypeComponent> {

    Destroy(self: OpcodeTypeComponent): void {
        OpcodeTypeComponent.Instance = null;
    }

}